/********************************************************
*  Monica Jimenez Anton                                 *
*  Juan Luis Martinez Cesteros                          *
*  Practicas - IGr                                     *
********************************************************/
#include <vcl.h>
#pragma hdrstop

#include "camara.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)
Camara::Camara(GLdouble eyeX,GLdouble eyeY,GLdouble eyeZ,
                GLdouble lookX,GLdouble lookY,GLdouble lookZ,
                GLdouble upX,GLdouble upY,GLdouble upZ){


     eye=new PV(eyeX,eyeY,eyeZ,1);
     look=new PV(lookX,lookY,lookZ,1);
     up=new PV(upX,upY,upZ,0);
     setView(eye,look,up);



}
void Camara::setView(PV * eye_, PV* look_, PV * up_){
    eye = eye_;
    look = look_;
    up = up_;
    n = new PV(eye->getX()-look->getX(),eye->getY()-look->getY(),eye->getZ()-look->getZ(),0);
    n->normalizacion();
    u = up->producto_vectorial(up,n);
    u->normalizacion();
    v = n->producto_vectorial(n,u);
    glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     gluLookAt(eye->getX(),eye->getY(),eye->getZ(),
               look->getX(),look->getY(),look->getZ(),
               up->getX(),up->getY(),up->getZ());

}
void Camara::roll(GLdouble ang){
    GLdouble cs=cos(M_PI/180*ang);
    GLdouble sn=sin(M_PI/180*ang);
    PV * nuevoU=u->copiar();
    PV * nuevoV=v->copiar();
    delete u;
    delete v;
    u=new PV(cs*nuevoU->getX()+sn*nuevoV->getX(),
             cs*nuevoU->getY()+sn*nuevoV->getY(),
             cs*nuevoU->getZ()+sn*nuevoV->getZ(),
             0);
    v=new PV(-sn*nuevoU->getX()+cs*nuevoV->getX(),
             -sn*nuevoU->getY()+cs*nuevoV->getY(),
             -sn*nuevoU->getZ()+cs*nuevoV->getZ(),
             0);

    setModelViewMatrix();

    delete nuevoU;
    delete nuevoV;


}
void Camara::yaw(GLdouble ang){
  GLdouble cs = cos(M_PI / 180 * ang);
  GLdouble sn = sin(M_PI / 180 * ang);

  PV * ucopy = u->copiar();
  PV * ncopy = n->copiar();

  delete u, delete n;

  
  n = new PV(cs * ncopy->getX() + sn * ucopy->getX(),
             cs * ncopy->getY() + sn * ucopy->getY(),
             cs * ncopy->getZ() + sn * ucopy->getZ(),
             0);
  u = new PV(cs * ucopy->getX() - sn * ncopy->getX(),
             cs * ucopy->getZ() - sn * ncopy->getY(),
             cs * ucopy->getY() - sn * ncopy->getZ(),
             0);

  delete ucopy;
  delete ncopy;

  setModelViewMatrix();		// informa a OpenGL
}

void Camara::pitch(GLdouble ang){
  GLdouble cs = cos(M_PI / 180 * ang);
  GLdouble sn = sin(M_PI / 180 * ang);


  PV * vcopy = v->copiar();
  PV * ncopy = n->copiar();

  delete v, delete n;

  n = new PV(cs * ncopy->getX() + sn * vcopy->getX(),
             cs * ncopy->getY() + sn * vcopy->getY(),
             cs * ncopy->getZ() + sn * vcopy->getZ(),
             1);
  v = new PV(cs * vcopy->getX() - sn * ncopy->getX(),
             cs * vcopy->getY() - sn * ncopy->getY(),
             cs * vcopy->getZ() - sn * ncopy->getZ(),
             1);

  delete vcopy;
  delete ncopy;
  setModelViewMatrix();		// informa a OpenGL
}


void Camara::slide(GLdouble delU,GLdouble delV,GLdouble delN){
  GLdouble eyex=delU * u->getX() + delV * v->getX() + delN * n->getX() + eye->getX();
  GLdouble eyey=delU * u->getY() + delV * v->getY() + delN * n->getY() + eye->getY();
  GLdouble eyez=delU * u->getZ() + delV * v->getZ() + delN * n->getZ() + eye->getZ();

  eye->setX(eyex);
  eye->setY(eyey);
  eye->setZ(eyez);
  
  setModelViewMatrix();		// informa a OpenGL

}

void Camara::ortogonal(GLdouble i,GLdouble d, GLdouble b, GLdouble t, GLdouble N, GLdouble F){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(i,d, b,t, N,F);
}

void Camara::perspectiva(GLfloat anguloVision, GLfloat proporcion, GLfloat N, GLfloat F){
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(anguloVision, proporcion, N, F);

}

void Camara::oblicua(GLdouble i,GLdouble d, GLdouble b, GLdouble t, GLdouble N, GLdouble F, PV* dir){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(i,d, b,t, N,F);

    if(dir->getZ()!=0 && (dir->getX()!=0 || dir->getY()!=0)){
        GLfloat p[16];
        for(int i = 1; i < 16;i++){
           p[i]=0;
        }
        p[0]=1;         p[5]=1;         p[15]=1;
        p[8]=-dir->getX()/dir->getZ();
        p[9]=-dir->getY()/dir->getZ();
	  p[10] = 1;
        glMultMatrixf(p);
    }


}


void Camara::setModelViewMatrix(){
  GLdouble m[16];
  m[0] =  u->getX(); m[4] =  u->getY(); m[8]  =  u->getZ();  m[12] = -eye->prodEscalar(eye,u);
  m[1] =  v->getX(); m[5] =  v->getY(); m[9]  =  v->getZ();  m[13] = -eye->prodEscalar(eye,v);
  m[2] =  n->getX(); m[6] =  n->getY(); m[10] =  n->getZ();  m[14] = -eye->prodEscalar(eye,n);
  m[3] =  0;         m[7] =  0;         m[11] =  0;          m[15] = 1.0;

  glMatrixMode(GL_MODELVIEW);
  glLoadMatrixd(m); // load OpenGL's modelview matrix
}








